package be.novelfaces.component.util;

import java.io.IOException;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.UIOutput;
import javax.faces.component.behavior.ClientBehavior;
import javax.faces.component.behavior.ClientBehaviorContext;
import javax.faces.component.behavior.ClientBehaviorHolder;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;

import be.novelfaces.component.util.attribute.PassThroughAttribute;
import be.novelfaces.component.util.attribute.PassThroughAttributes;

public interface RenderUtils {

	final String XHTML_CONTENT_TYPE = "application/xhtml+xml";
	final String XHTML_ATTRIBUTE_PREFIX = "xml:";

	void decodeUIInput(FacesContext facesContext, UIComponent component);

	void decodeClientBehaviors(FacesContext facesContext, UIComponent component);

	void checkParamValidity(FacesContext facesContext, UIComponent component,
			Class<? extends Object> compClass);

	boolean isDisabledOrReadOnly(UIComponent component);

	boolean isDisabled(UIComponent component);

	boolean isReadOnly(UIComponent component);

	String getPathToComponent(UIComponent component);

	Object getConvertedUIOutputValue(FacesContext facesContext,
			UIOutput component, Object newSubmittedValue)
			throws ConverterException;

	String getStringValue(FacesContext facesContext, UIComponent component)
			throws ConverterException;

	/**
	 * Find the proper Converter for the given {@link UIOutput} component.
	 * 
	 * @throws FacesException
	 *             if the Converter could not be created
	 * @param facesContext
	 *            the {@link FacesContext} for the current request
	 * @param component
	 *            {@link UIOutput} of interest
	 * @return the Converter or null if no Converter specified or needed
	 */
	Converter findUIOutputConverter(FacesContext facesContext,
			UIOutput component);

	/**
	 * <p>
	 * Render any passThrough attributes, where we simply just output the raw
	 * name and value of the attribute.
	 * </p>
	 * 
	 * @param facesContext
	 *            the {@link FacesContext} for the current request
	 * @param component
	 *            {@link UIComponent} of interest
	 * @param passThroughAttributes
	 *            a {@link LinkedHashSet} of passThroughAttributes (
	 *            {@link PassThroughAttribute}) to be processed
	 * @throws IOException
	 *             if an error occurs writing the attributes
	 */
	void renderPassThroughAttributes(FacesContext facesContext,
			UIComponent component, PassThroughAttributes passThroughAttributes)
			throws IOException;

	/**
	 * <p>
	 * Render any passThrough attributes, where we simply just output the raw
	 * name and value of the attribute.
	 * </p>
	 * 
	 * @param facesContext
	 *            the {@link FacesContext} for the current request
	 * @param component
	 *            {@link UIComponent} of interest
	 * @param passThroughAttributes
	 *            a {@link LinkedHashSet} of passThroughAttributes (see
	 *            {@link PassThroughAttribute}) to be processed
	 * @param behaviors
	 *            the behaviors for this component, or null if component is not
	 *            a {@link ClientBehaviorHolder}
	 * @throws IOException
	 *             if an error occurs writing the attributes
	 */
	void renderPassThroughAttributes(FacesContext facesContext,
			UIComponent component, PassThroughAttributes passThroughAttributes,
			Map<String, List<ClientBehavior>> behaviors) throws IOException;

	/**
	 * Renders an event handler script (eg. "onclick" or "onmouseover"). This
	 * may require chaining together the user-specified event handler and any
	 * scripts from the behaviors. If component is disabled, behavior scripts
	 * are not rendered.
	 * 
	 * @param facesContext
	 *            the {@link FacesContext} for this request.
	 * @param component
	 *            the {@link UIComponent} that we are rendering
	 * @param params
	 *            any parameters that should be included by "submitting"
	 *            scripts.
	 * @param eventHandlerName
	 *            the name of the event handler attribute to render (eg.
	 *            "onclick" or "ommouseover")
	 * @param eventHandlerValue
	 *            the user-specified value for the handler attribute
	 * @param behaviorEventName
	 *            the name of the behavior event that corresponds to this
	 *            handler (eg. "action" or "mouseover").
	 * @param behaviors
	 *            the behaviors for this event.
	 * @throws IOException
	 *             if an error occurs writing the event handler
	 */
	void renderEventHandler(FacesContext facesContext, UIComponent component,
			Collection<ClientBehaviorContext.Parameter> params,
			String eventHandlerName, Object eventHandlerValue,
			String behaviorEventName, List<ClientBehavior> behaviors)
			throws IOException;

	void renderPassThroughAttribute(FacesContext facesContext,
			PassThroughAttribute passThroughAttribute, Object attributeValue)
			throws IOException;

	boolean isDefaultAttributeValue(Object value);

}